import { Flex, Input } from 'antd';
import { useEffect, useState } from 'react';
import styles from './ci.module.less';

const parseCoordinate = (input: string): [number, number] | null => {
  // Remove whitespace and split into parts
  const cleaned = input.trim().replace(/\s+/g, ' ');

  // Try different formats:

  // 1. Simple decimal format (-134.5,44.56 or -134.5 44.56)
  const decimalMatch = cleaned.match(/^(-?\d+\.?\d*)[, ](-?\d+\.?\d*)$/);
  if (decimalMatch) {
    const lon = parseFloat(decimalMatch[1]);
    const lat = parseFloat(decimalMatch[2]);
    if (!Number.isNaN(lon) && !Number.isNaN(lat)) {
      return [lon, lat];
    }
  }

  // 2. Cardinal direction format (E 134.5 N 44.56 or W134.5 S44.56)
  const cardinalMatch = cleaned.match(
    /^([EW])\s*(-?\d+\.?\d*)[, ]([NS])\s*(-?\d+\.?\d*)$/i,
  );
  if (cardinalMatch) {
    const lonSign = cardinalMatch[1].toUpperCase() === 'E' ? 1 : -1;
    const latSign = cardinalMatch[3].toUpperCase() === 'N' ? 1 : -1;
    const lon = parseFloat(cardinalMatch[2]) * lonSign;
    const lat = parseFloat(cardinalMatch[4]) * latSign;
    if (!Number.isNaN(lon) && !Number.isNaN(lat)) {
      return [lon, lat];
    }
  }

  // 3. Degree-minute-second format (134°6′ 44°56′ or 134°6' 44°56')
  const dmsMatch = cleaned.match(
    /^(-?\d+)°(\d+)[′'](\d+\.?\d*)["″]?\s*(-?\d+)°(\d+)[′'](\d+\.?\d*)["″]?$/,
  );
  if (dmsMatch) {
    const lonDeg = parseFloat(dmsMatch[1]);
    const lonMin = parseFloat(dmsMatch[2]);
    const lonSec = parseFloat(dmsMatch[3]);
    const latDeg = parseFloat(dmsMatch[4]);
    const latMin = parseFloat(dmsMatch[5]);
    const latSec = parseFloat(dmsMatch[6]);

    if (
      !Number.isNaN(lonDeg) &&
      !Number.isNaN(lonMin) &&
      !Number.isNaN(lonSec) &&
      !Number.isNaN(latDeg) &&
      !Number.isNaN(latMin) &&
      !Number.isNaN(latSec)
    ) {
      const lon = lonDeg + lonMin / 60 + lonSec / 3600;
      const lat = latDeg + latMin / 60 + latSec / 3600;
      return [lon, lat];
    }
  }

  // 4. DMS with cardinal directions format (23°19'13"N 113°17'1"E or 113°17'1"E 23°19'13"N)
  const dmsCardinalMatch = cleaned.match(
    /^(\d+)°(\d+)'(\d+\.?\d*)["″]?([NS])\s+(\d+)°(\d+)'(\d+\.?\d*)["″]?([EW])$|^(\d+)°(\d+)'(\d+\.?\d*)["″]?([EW])\s+(\d+)°(\d+)'(\d+\.?\d*)["″]?([NS])$/i,
  );
  if (dmsCardinalMatch) {
    let lat: number, lon: number;

    if (dmsCardinalMatch[1]) {
      // First format: lat lon (23°19'13"N 113°17'1"E)
      const latDeg = parseFloat(dmsCardinalMatch[1]);
      const latMin = parseFloat(dmsCardinalMatch[2]);
      const latSec = parseFloat(dmsCardinalMatch[3]);
      const latDir = dmsCardinalMatch[4].toUpperCase();
      const lonDeg = parseFloat(dmsCardinalMatch[5]);
      const lonMin = parseFloat(dmsCardinalMatch[6]);
      const lonSec = parseFloat(dmsCardinalMatch[7]);
      const lonDir = dmsCardinalMatch[8].toUpperCase();

      lat = (latDeg + latMin / 60 + latSec / 3600) * (latDir === 'N' ? 1 : -1);
      lon = (lonDeg + lonMin / 60 + lonSec / 3600) * (lonDir === 'E' ? 1 : -1);
    } else {
      // Second format: lon lat (113°17'1"E 23°19'13"N)
      const lonDeg = parseFloat(dmsCardinalMatch[9]);
      const lonMin = parseFloat(dmsCardinalMatch[10]);
      const lonSec = parseFloat(dmsCardinalMatch[11]);
      const lonDir = dmsCardinalMatch[12].toUpperCase();
      const latDeg = parseFloat(dmsCardinalMatch[13]);
      const latMin = parseFloat(dmsCardinalMatch[14]);
      const latSec = parseFloat(dmsCardinalMatch[15]);
      const latDir = dmsCardinalMatch[16].toUpperCase();

      lat = (latDeg + latMin / 60 + latSec / 3600) * (latDir === 'N' ? 1 : -1);
      lon = (lonDeg + lonMin / 60 + lonSec / 3600) * (lonDir === 'E' ? 1 : -1);
    }

    if (!Number.isNaN(lat) && !Number.isNaN(lon)) {
      return [lon, lat];
    }
  }

  return null;
};

export const CoordinateInput = ({
  value,
  onChange,
}: {
  value: string | null;
  onChange: (val: [number, number] | null) => void;
}) => {
  const [inputValue, setInputValue] = useState('');

  useEffect(() => {
    // Only update input value when value is externally set to null
    // Don't override user's input string when value is set from parsing
    if (value === null) {
      setInputValue('');
    } else {
      if (inputValue === '') {
        setInputValue(value?.toString() || '');
      }
    }
  }, [value]);

  const [errorMessage, setErrorMessage] = useState('');
  const [valueStr, setValueStr] = useState('');

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const val = e.target.value;
    setInputValue(val);

    if (val.trim() === '') {
      onChange(null);
      setErrorMessage('');
      return;
    }

    const parsed = parseCoordinate(val);
    if (parsed === null) {
      setErrorMessage('Invalid coordinate format');
    } else {
      const [lon, lat] = parsed;
      if (lon < -180 || lon > 180) {
        setErrorMessage('Longitude must be between -180 and 180');
      } else if (lat < -90 || lat > 90) {
        setErrorMessage('Latitude must be between -90 and 90');
      } else {
        setErrorMessage('');
        setValueStr(`经度：${lon.toFixed(6)} , 纬度：${lat.toFixed(6)}`);
      }
    }
    onChange(parsed);
  };

  return (
    <Flex gap={8} vertical>
      <Input
        type="text"
        value={inputValue}
        onChange={handleChange}
        style={{ width: 264, marginRight: 5 }}
        title="Enter coordinates (e.g. -134.5,44.56 or E 134.5 N 44.56 or 23°19'13N 113°17'1E)"
        placeholder="Enter coordinates (e.g. -134.5,44.56 or E 134.5 N 44.56 or 23°19'13N 113°17'1E)"
      />
      <div
        className={styles.info}
        style={{ color: errorMessage ? 'red' : 'inherit' }}
      >
        {errorMessage ||
          valueStr ||
          (value
            ? `${value}`
            : '(e.g. -134.5,44.56 or E 134.5 N 44.56 or 23°19\'13"N 113°17\'1"E)')}
      </div>
    </Flex>
  );
};
